from __future__ import absolute_import
import re
from forest.resource import Resource, ValidationError
import os.path

class Modify(Resource):
    ''' Allows matching and replacing something in a files lines.

        modify[*].re or modify[*].match must be specified for each modification.

        Example::

            resources:
              - $: modify
                file: /etc/fuse.conf
                re: "some regular expression"
                match: "# mount_max = 1000"
                replace: "mount_max = 1000"

        .. describe:: file

            The file to modify.

        .. describe:: match

            A simple string to match for. Match matches one line at a time.

        .. describe:: re

            A regular expression to match. The regular expression is applied to the whole file.

        .. describe:: replace

            What to replace when matched.
    '''

    __register__ = 'modify'

    def __init__(self, config, value):
        super(File, self).__init__(config, value)
        self.fullpath = config.join_install_root(self.get_file())

    def get_id(self):
        return ' '.join(['modify:', self.value.get('file')])

    def get_file(self):
        return self.value.get('file')

    def get_replace(self):
        return self.value.get('replace')

    def get_match(self):
        return self.value.get('match', None)

    def get_re(self):
        return self.value.get('re', None)

    def validate(self):

        valid_keys = ['file','re','match','replace']

        for k in self.value.iterkeys():
            if k in valid_keys:
                continue
            raise ValidationError("Undefined modify option %s" % k)

        necessary_keys = ['file', 'replace']

        for necessary in necessary_keys:
            if necessary in self.value:
                continue
            raise ValidationError('Missing modify option {}. Please specify it.'.format(necessary))

        regex = self.get_re()
        if regex is not None:
            try:
                re.compile(regex)
            except re.error as err:
                raise ValidationError('Invalid regex "{0}"! : {1}'.format(regex, err))

        if not os.path.exists(self.fullpath):
            raise ValidationError('Cannot modify a non-existing file: {}'.format(self.fullpath))

        elif not os.path.isfile(self.fullpath):
            raise ValidationError('Cannot modify a directory: {} - need a file'.format(self.fullpath))
